import { Injectable } from '@nestjs/common';
import { DepartDto, DepartUpdateDto } from './dto/depart.dto';
import { v4 as uuidv4 } from 'uuid';
import { MongodbService } from '../../database/mongodb/mongodb.service';
import { BusinessException } from '../../types/exception/business.exception';
import { ERR_MSG } from '../../types/errcode';
import * as _ from 'lodash';

@Injectable()
export class DepartService {
  constructor(private readonly _mongodbService: MongodbService) {}

  /**
   * 将扁平列表转换为树形结构
   * @param list 扁平数据列表
   * @param option 配置项 { key: 节点标识字段, parent: 父节点引用字段, children: 子节点字段名 }
   */
  /**
   * 将扁平列表转换为树形结构
   * @param list 扁平数据列表
   * @param option 配置项 { key: 节点标识字段, parent: 父节点引用字段, children: 子节点字段名 }
   */
  list2Tree(
    list: any[],
    option: {
      key?: string; // 默认 '_id'
      parent?: string; // 默认 'parentId'
      children?: string; // 默认 'children'
    } = { key: '_id', parent: 'parentId', children: 'children' },
  ): any[] {
    const { key = '_id', parent = 'parentId', children = 'children' } = option;

    const map = new Map<string, any>();
    const tree: any[] = [];

    // 第一步：把所有节点放进 map 中，统一转成字符串作为 key
    for (const node of list) {
      const nodeId = String(node[key]);
      map.set(nodeId, { ...node });
    }

    // 第二步：遍历每个节点，找到其父节点并添加到对应 children 数组中
    for (const node of list) {
      const parentId = String(node[parent]);

      if (parentId === '0') {
        // 根节点直接推入树
        const nodeId = String(node[key]);
        tree.push(map.get(nodeId));
      } else {
        // 子节点：查找父节点是否存在
        const parentNode = map.get(parentId);
        if (parentNode) {
          if (!parentNode[children]) {
            parentNode[children] = [];
          }
          const nodeId = String(node[key]);
          parentNode[children].push(map.get(nodeId));
        }
      }
    }

    return tree;
  }

  // 获取部门树
  async getdepartTree(id: string) {
    let treeData: any[] = [];
    // 先获取所有的部门列表，lean()清除隐藏字段
    const departList = await this._mongodbService.DepartModel.find(
      {}, // 空查询条件表示全部
      {
        __v: 0, // 排除 __v
        createdAt: 0,
        updatedAt: 0,
      },
    ).lean();

    // 根据现有的数据进行排序
    departList.sort(function (a, b) {
      return a.sort - b.sort;
    });

    treeData = this.list2Tree(departList);

    if (id) {
      // 查找目标节点
      const result = this._findNode(treeData, id);

      if (!result) {
        throw new BusinessException(ERR_MSG.DEPART_NOT_EXIST);
      }
      return { treeData: [result] };
    }

    return { treeData };
  }

  /**
   * 在树中查找指定 _id 的节点
   * @param tree 树形结构
   * @param id 要查找的节点 ID
   */
  private _findNode(tree: any[], id: string): any {
    for (const node of tree) {
      if (node._id.toString() === id) {
        return node;
      }

      if (node.children && node.children.length > 0) {
        const found = this._findNode(node.children, id);
        if (found) return found;
      }
    }
    return null;
  }

  // 获取部门列表
  async getdepartList(req) {
    const { skip, limit } = req.herin;

    const findObj: any = {
      $and: [],
    };

    const list = await this._mongodbService.DepartModel.aggregate([{ $skip: skip ? skip : 0 }, { $limit: limit ? limit : 10 }, { $project: { departName: 1, parentId: 1, _id: 1 } }]);

    const total = await this._mongodbService.DepartModel.countDocuments(findObj);

    return { list, total };
  }

  // 获取部门信息
  async getdepartInfo(id: string) {
    // 查询部门信息
    const info = await this._mongodbService.DepartModel.findById(id)
      .select({ __v: 0, createdAt: 0, updatedAt: 0 }) // 排除不需要的字段
      .lean()
      .exec();

    if (!info) {
      throw new BusinessException(ERR_MSG.DEPART_NOT_EXIST);
    }

    return { info };
  }

  // 新增部门
  async adddepart(req, DepartDto: DepartDto) {
    // 校验当前名称的部门是否已存在
    const checkExist = await this._mongodbService.DepartModel.findOne({
      departName: DepartDto.departName,
    });
    if (!_.isEmpty(checkExist)) {
      throw new BusinessException(ERR_MSG.DEPART_IS_EXIST);
    }

    // 存储
    const returnData = await this._mongodbService.DepartModel.create({
      departName: DepartDto.departName ?? '',
      parentId: DepartDto.parentId ?? '',
      sort: DepartDto.sort ?? 0,
    });

    return { msg: returnData.departName + ' - 部门创建成功' };
  }

  // 更新部门
  async updatedepart(req, DepartUpdateDto: DepartUpdateDto) {
    const { id, ...updateData } = DepartUpdateDto;

    const depart = await this._mongodbService.DepartModel.findOne({
      _id: id,
    });
    if (_.isEmpty(depart)) {
      throw new BusinessException(ERR_MSG.DEPART_NOT_EXIST);
    }

    const res = await this._mongodbService.DepartModel.updateOne({ _id: id }, { $set: updateData });
    if (res.modifiedCount > 0) {
      return { msg: '部门更新成功' };
    } else {
      return { msg: '部门更新失败' };
    }
  }

  // 删除部门
  async deletedepart(req, body: { ids: string[] }) {
    const { ids } = body;

    if (ids.length <= 0) {
      throw new BusinessException({
        msg: '请提供要删除的部门id',
        code: '10001',
      });
    }

    // 判断所传的id是否存在
    const depart = await this._mongodbService.DepartModel.findOne({
      _id: { $in: ids },
    });
    if (_.isEmpty(depart)) {
      throw new BusinessException(ERR_MSG.DEPART_NOT_EXIST);
    }

    // 判断当前部门下是否有绑定的人员，如果有，无法删除 --TODO

    // 判断当前部门下是否有子部门，如果有，无法删除

    const isHasChildDept = await this.checkChildDept(ids);
    if (isHasChildDept) {
      throw new BusinessException(ERR_MSG.DEPART_HAS_CHILD_NOT_DELETE);
    }

    const res = await this._mongodbService.DepartModel.deleteMany({
      _id: { $in: ids },
    });
    if (res.deletedCount > 0) {
      return { msg: '删除部门成功' };
    } else {
      return { msg: '删除部门失败' };
    }
  }

  // 判断当前部门ids是否有子部门
  async checkChildDept(ids: string[]): Promise<boolean> {
    let result = false;
    // 查询所有部门
    const allDepts = await this._mongodbService.DepartModel.find({}, { parentId: 1, _id: 0 }).lean();

    // 检查是否存在子部门
    for (const dept of allDepts) {
      if (ids.includes(dept.parentId)) {
        result = true; // 找到子部门
      }
    }

    return result; // 没有子部门
  }
}
